package com.shuyuntu.proposal.service;

import com.shuyuntu.proposal.dao.*;
import com.shuyuntu.proposal.entity.*;
import com.shuyuntu.proposal.enums.EProposalState;
import com.shuyuntu.proposal.enums.EProposalType;
import org.hibernate.Hibernate;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * Created by limeng on 16-4-17.
 */
@Service("proposalService")
public class ProposalService {
    /**
     * 发布提案
     * @param proposal 待存入数据库的提案
     * @return true/false
     */
    @Transactional
    public boolean publishProposal(Proposal proposal) {
        try {
            proposalDao.insert(proposal);

            Set<Attachment> list = proposal.getAttachments();
            if (list != null && list.size() > 0) {
                for (Attachment attachment : list) {

                    Attachment atc = new Attachment();
                    atc.setFilename(attachment.getFilename());
                    atc.setProposal(proposal);
                    atc.setRealName(attachment.getRealName());
                    atc.setSize(attachment.getSize());
                    atc.setPath("attachments");

                    attachmentDao.insert(atc);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }

        return true;
    }

    /**
     * 分页搜索提案
     * @param pageSize 页面大小
     * @param pageNo 页数
     * @param reqMap 条件map
     * @param rowCount 第二返回值,行数
     * @return 结果集
     */
    @Transactional
    public List<Proposal> doSearch(Integer pageSize, Integer pageNo, Map<String, Object> reqMap, StringBuffer rowCount) {

        Criterion[] criterionArr = new Criterion[12];
        //数组游标,此处不能使用List,只能用这种方式
        int cursor = 0;

        Object authorId = reqMap.get("authorId");
        Object title = reqMap.get("title");
        Object authorName = reqMap.get("authorName");
        Object proposalState = reqMap.get("proposalState");
        Object proposalType = reqMap.get("proposalType");
        Object authorDepartmentId = reqMap.get("authorDepartmentId");
        Object hostDepartmentId = reqMap.get("hostDepartmentId");
        Object startTime = reqMap.get("startTime");
        Object endTime = reqMap.get("endTime");

        if (authorId != null) {
            criterionArr[cursor++] = (Restrictions.eq("author.id", authorId));
        }
        if (authorName != null && !authorName.equals("")) {
            List<Delegate> delegates = delegateDao.queryList(
                    Restrictions.eq("name", authorName));
            criterionArr[cursor++] = (Restrictions.in("author", delegates));
        }
        if (title != null && !title.equals("")) {
            criterionArr[cursor++] = (Restrictions.like(
                    "title", (String)title, MatchMode.ANYWHERE));
        }
        if (proposalState != null) {
            Integer stateVal = (Integer)proposalState;
            if (stateVal != -1) {
                criterionArr[cursor++] = (Restrictions.eq(
                        "proposalState", EProposalState.values()[(Integer) proposalState]));
            } else {
                criterionArr[cursor++] = Restrictions.or(
                        Restrictions.eq("proposalState", EProposalState.WAIT_SECOND_MOTION),
                        Restrictions.eq("proposalState", EProposalState.PUTTED_INTO_EFFECT),
                        Restrictions.eq("proposalState", EProposalState.SUGGESTED),
                        Restrictions.eq("proposalState", EProposalState.REGISTERED),
                        Restrictions.eq("proposalState", EProposalState.UNREGISTERED)
                );
            }
        } else {
            criterionArr[cursor++] = (Restrictions.ne(
                    "proposalState", EProposalState.DELETED));
        }
        if (proposalType != null) {
            criterionArr[cursor++] = (Restrictions.eq(
                    "proposalType", EProposalType.values()[(Integer) proposalType]));
        }
        if (hostDepartmentId != null) {
            criterionArr[cursor++] = Restrictions.eq("hostDepartment.id", hostDepartmentId);
        }
        if (authorDepartmentId != null) {
            List<Delegate> list = delegateDao.queryList(Restrictions.eq("department.id", authorDepartmentId));
            criterionArr[cursor++] = Restrictions.in("author", list);
        }
        SimpleDateFormat sdf = null;
        if (startTime != null) {
            sdf = new SimpleDateFormat("yyyy-MM-dd");
            try {
                Date startDate = sdf.parse((String)startTime);
                criterionArr[cursor++] = Restrictions.ge("updateTime", startDate);
            } catch (ParseException e) {

            }
        }
        if (endTime != null) {
            if (sdf == null) {
                sdf = new SimpleDateFormat("yyyy-MM-dd");
            }
            try {
                Date endDate = sdf.parse((String)endTime);
                Calendar calendar = Calendar.getInstance();
                calendar.setTime(endDate);
                calendar.add(Calendar.DAY_OF_MONTH, 1);
                endDate = calendar.getTime();
                criterionArr[cursor] = Restrictions.le("updateTime", endDate);
            } catch (ParseException e) {

            }
        }

        return proposalDao.querySearchPageList(pageNo, pageSize, rowCount, Order.desc("id"), criterionArr);
    }

    @Transactional
    public List<Proposal> searchAssist(
            Integer pageSize,
            Integer pageNo,
            String assistDepartmentId,
            StringBuffer rowCount) {
        return proposalDao.queryProposalsByAssistDepartmentId(
                pageNo, pageSize, assistDepartmentId, rowCount);
    }

    @Transactional
    public Proposal getProposalById(Integer id) {
        Proposal proposal = proposalDao.queryById(id);

        return proposal;
    }

    @Transactional
    public Proposal getProposalAndIncreaseClickCountById(int id) {
        Proposal proposal = proposalDao.queryById(id);
        if (proposal != null) {
            int clickCount = proposal.getClickCount() + 1;
            proposal.setClickCount(clickCount);
            proposalDao.update(proposal);
        }

        return proposal;
    }

    @Transactional
    public long getProposalCount(String userId, EProposalState state) {
        Criterion cr1 = Restrictions.eq("author.id", userId);
        if (state == null) {
            return proposalDao.queryCount(cr1);
        }
        Criterion cr2 = Restrictions.eq("proposalState", state);
        return proposalDao.queryCount(cr1, cr2);
    }

    @Transactional
    public int checkPass(int proposalId) {
        Proposal proposal = proposalDao.queryById(proposalId);
        if (proposal.getProposalState() == EProposalState.UNCHECKED) {
            try {
                proposal.setProposalState(EProposalState.WAIT_SECOND_MOTION);
                proposalDao.update(proposal);
                return 0;
            } catch (Exception e) {
                e.printStackTrace();
                return 1;
            }
        }
        return 2;
    }

    @Transactional
    public int registPass(Integer proposalId,
                          EProposalType proposalType,
                          String hostDepartmentId,
                          List<String> assistDepartmentIdList) {
        Proposal proposal = proposalDao.queryById(proposalId);
        if (proposal.getProposalState() == EProposalState.UNREGISTERED) {
            try {
                proposal.setProposalState(EProposalState.REGISTERED);
                proposal.setProposalType(proposalType);
                proposal.setHostDepartment(departmentDao.queryById(hostDepartmentId));
                if (assistDepartmentIdList != null) {
                    for (String assistDepartmentId : assistDepartmentIdList) {
                        Department department = departmentDao.queryById(assistDepartmentId);
                        if (department != null) {
                            proposal.getAssistDepartments().add(department);
                        }
                    }
                }
                proposal.setPublishTime(new Date());
                proposalDao.update(proposal);
                return 0;
            } catch (Exception e) {
                e.printStackTrace();
                return 1;
            }
        }
        return 2;
    }

    /**
     * 主办部门无异议的时候,调用的方法
     * @param proposalId 提案的id
     * @param handlerId 操作者的id,用来判断是否属于该部门
     * @return 0:操作成功;1:数据库异常;2:提案状态不对;3:操作者不属于该部门
     */
    @Transactional
    public int feedbackPass(Integer proposalId, String handlerId) {
        Proposal proposal = proposalDao.queryById(proposalId);
        Delegate delegate = delegateDao.queryById(handlerId);
        if (!proposal.getHostDepartment().getId().equals(delegate.getDepartment().getId())) {
            return 3;
        }
        if (proposal.getProposalState() == EProposalState.REGISTERED) {
            try {
                proposal.setProposalState(EProposalState.PUTTED_INTO_EFFECT);
                proposalDao.update(proposal);
                return 0;
            } catch (Exception e) {
                e.printStackTrace();
                return 1;
            }
        }
        return 2;
    }

    @Transactional
    public void autoFeedbackPass() {
        SystemConfig systemConfig = systemConfigService.getLatestConfig();
        Date now = new Date();

        if (now.after(systemConfig.getEndTime())) return;

        Criterion cr1 = Restrictions.eq("proposalState", EProposalState.REGISTERED);

        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.DAY_OF_YEAR, calendar.get(Calendar.DAY_OF_YEAR - 10));

        Date criTime = calendar.getTime();
        Criterion cr2 = Restrictions.le("publishTime", criTime);
        List<Proposal> proposals = proposalDao.queryList(cr1, cr2);
        for (Proposal proposal : proposals) {
            proposal.setProposalState(EProposalState.PUTTED_INTO_EFFECT);
            proposalDao.update(proposal);
        }
    }

    @Transactional
    public int feedbackFailed(Integer proposalId, String refuseResult, String handlerId) {
        Proposal proposal = proposalDao.queryById(proposalId);
        Delegate delegate = delegateDao.queryById(handlerId);
        if (!proposal.getHostDepartment().getId().equals(delegate.getDepartment().getId())) {
            return 3;
        }
        if (proposal.getProposalState() == EProposalState.REGISTERED) {
            try {
                proposal.setProposalState(EProposalState.UNREGISTERED);
                proposal.setRefuseResult(refuseResult);
                proposalDao.update(proposal);
                return 0;
            } catch (Exception e) {
                e.printStackTrace();
                return 1;
            }
        }
        return 2;
    }

    @Transactional
    public int delegateFeedback(int proposalId, String userId, String feedbackInfo) {
        Proposal proposal = proposalDao.queryById(proposalId);
        if (proposal.getAuthor().getId().equals(userId)) {
            if (proposal.getProposalState() == EProposalState.PUTTED_INTO_EFFECT) {
                try {
                    proposal.setFeedbackInfo(feedbackInfo);
                    proposalDao.update(proposal);
                    return 0;
                } catch (Exception e) {
                    e.printStackTrace();
                    return 3;
                }
            } else {
                return 1;
            }
        } else {
            return 2;
        }
    }

    @Transactional
    public int checkFailed(int proposalId, String result) {
        Proposal proposal = proposalDao.queryById(proposalId);
        if (proposal.getProposalState() == EProposalState.UNCHECKED) {
            try {
                proposal.setProposalState(EProposalState.INVALID);
                proposal.setRefuseResult(result);
                proposalDao.update(proposal);
                return 0;
            } catch (Exception e) {
                e.printStackTrace();
                return 1;
            }
        }
        return 2;
    }

    @Transactional
    public int registFailed(int proposalId, String refuseResult) {
        Proposal proposal = proposalDao.queryById(proposalId);
        if (proposal.getProposalState() == EProposalState.UNREGISTERED) {
            try {
                proposal.setProposalState(EProposalState.SUGGESTED);
                proposal.setRefuseResult(refuseResult);
                proposalDao.update(proposal);
                return 0;
            } catch (Exception e) {
                e.printStackTrace();
                return 1;
            }
        }
        return 2;
    }

    /**
     * 删除提案
     * @param proposal 提案
     * @return true/false
     */
    @Transactional
    public boolean deleteProposal(Proposal proposal) {
        try {
            proposal.setProposalState(EProposalState.DELETED);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    @Transactional
    public boolean updateProposal(Proposal proposal) {
        try {
            proposalDao.update(proposal);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    @Transactional
    public List<Proposal> getNewProposalList(int pageSize, int pageNo, StringBuffer rowCount) {
        Criterion criterion = Restrictions.or(
            Restrictions.eq("proposalState", EProposalState.WAIT_SECOND_MOTION),
            Restrictions.eq("proposalState", EProposalState.UNREGISTERED),
            Restrictions.eq("proposalState", EProposalState.REGISTERED),
            Restrictions.eq("proposalState", EProposalState.PUTTED_INTO_EFFECT));
        Order order = Order.desc("updateTime");
        return proposalDao.querySearchPageList(pageNo, pageSize, rowCount, order, criterion);
    }

    @Transactional
    public List<Proposal> getHotestProposalList(int pageSize, int pageNo, StringBuffer rowCount) {
        Criterion criterion = Restrictions.or(
                Restrictions.eq("proposalState", EProposalState.WAIT_SECOND_MOTION),
                Restrictions.eq("proposalState", EProposalState.UNREGISTERED),
                Restrictions.eq("proposalState", EProposalState.REGISTERED),
                Restrictions.eq("proposalState", EProposalState.PUTTED_INTO_EFFECT));
        Order order = Order.desc("clickCount");
        return proposalDao.querySearchPageList(pageNo, pageSize, rowCount, order, criterion);
    }

    @Transactional
    public List<Proposal> getProposalsByConfigId(int configId, int pageSize, int pageNo, StringBuffer rowCount) {
        SystemConfig config = systemConfigService.getSystemConfigById(configId);

        Calendar calendar = Calendar.getInstance();
        calendar.setTime(config.getEndTime());
        calendar.add(Calendar.DAY_OF_MONTH, 1);
        Date endDate = calendar.getTime();

        Criterion criterion = Restrictions.and(Restrictions.or(
                Restrictions.eq("proposalState", EProposalState.WAIT_SECOND_MOTION),
                Restrictions.eq("proposalState", EProposalState.UNREGISTERED),
                Restrictions.eq("proposalState", EProposalState.REGISTERED),
                Restrictions.eq("proposalState", EProposalState.PUTTED_INTO_EFFECT)),
                Restrictions.and(Restrictions.ge("updateTime", config.getStartTime()),
                Restrictions.le("updateTime", endDate)));
        Order order = Order.desc("updateTime");
        return proposalDao.querySearchPageList(pageNo, pageSize, rowCount, order, criterion);    }



    /**********依赖注入相关↓***********/
    @Resource
    IProposalDao proposalDao;
    @Resource
    IAttachmentDao attachmentDao;
    @Resource
    IDepartmentDao departmentDao;
    @Resource
    IDelegateDao delegateDao;
    @Resource
    SystemConfigService systemConfigService;
    @Resource(name = "sessionFactory")
    SessionFactory sessionFactory;

    public IProposalDao getProposalDao() {
        return proposalDao;
    }

    public void setProposalDao(IProposalDao proposalDao) {
        this.proposalDao = proposalDao;
    }

    public IDelegateDao getDelegateDao() {
        return delegateDao;
    }

    public void setDelegateDao(IDelegateDao delegateDao) {
        this.delegateDao = delegateDao;
    }

    public IAttachmentDao getAttachmentDao() {
        return attachmentDao;
    }

    public void setAttachmentDao(IAttachmentDao attachmentDao) {
        this.attachmentDao = attachmentDao;
    }

    public IDepartmentDao getDepartmentDao() {
        return departmentDao;
    }

    public void setDepartmentDao(IDepartmentDao departmentDao) {
        this.departmentDao = departmentDao;
    }

    public SessionFactory getSessionFactory() {
        return sessionFactory;
    }

    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }

    public SystemConfigService getSystemConfigService() {
        return systemConfigService;
    }

    public void setSystemConfigService(SystemConfigService systemConfigService) {
        this.systemConfigService = systemConfigService;
    }
}
